﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.Text.RegularExpressions;

namespace CodeSnippetsEditor
{
    public partial class frmMain : Form
    {
        #region Cesty ke slozkam se snippety

        private string PathVS2005VB = 
            Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + 
            @"\Visual Studio 2005\Code Snippets\VB\My Code Snippets";
        private string PathVS2005CS = 
            Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + 
            @"\Visual Studio 2005\Code Snippets\Visual C#\My Code Snippets";
        private string PathVS2008VB = 
            Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + 
            @"\Visual Studio 2008\Code Snippets\VB\My Code Snippets";
        private string PathVS2008CS = 
            Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + 
            @"\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets";

        #endregion


        #region Promenne formulare

        private CodeSnippets cs = new CodeSnippets();
        private bool isSnippetLoaded;
        private bool isSnippetChanged;

        #endregion


        #region Kontruktory

        /// <summary>
        /// Initializes a new instance of the <see cref="frmMain"/> class.
        /// </summary>
        public frmMain()
        {
            InitializeComponent();
            SetEnabledSnippetControls(false);
        }

        #endregion


        #region Vlastnosti

        /// <summary>
        /// Gets or sets a value indicating whether this instance is snippet changed.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is snippet changed; otherwise, <c>false</c>.
        /// </value>
        private bool IsSnippetChanged
        {
            get
            {
                return isSnippetChanged;
            }
            set
            {
                if (isSnippetChanged != value)
                {
                    isSnippetChanged = value;

                    SetEnabledSnippetControls(isSnippetChanged);
                }
            }
        }

        #endregion


        #region Obsluha udalosti formulare

        /// <summary>
        /// Handles the Load event of the frmMain control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void frmMain_Load(object sender, EventArgs e)
        {
            //naplni dropdownlist s jazyky
            ddlLanguage.Items.Clear();
            ddlLanguage.Items.Add(new DropDownListItem("C#", "csharp"));
            ddlLanguage.Items.Add(new DropDownListItem("Visual Basic", "vb"));

            //naplni dropdownlist s umistenim
            ddlKind.Items.Clear();
            ddlKind.Items.Add(new DropDownListItem("Deklarace tříd a typů", "type decl"));
            ddlKind.Items.Add(new DropDownListItem("Deklarace funkcí a vlastností", "method decl"));
            ddlKind.Items.Add(new DropDownListItem("Kód uvnitř metody", "method body"));

            //naplni strom se snippety
            RefreshSnippetsTree();
        }

        /// <summary>
        /// Handles the Click event of the tsbtnRefreshTree control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnRefreshTree_Click(object sender, EventArgs e)
        {
            RefreshSnippetsTree();
        }

        /// <summary>
        /// Handles the AfterSelect event of the tvSnippets control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.TreeViewEventArgs"/> instance containing the event data.</param>
        private void tvSnippets_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //je-li vybrany uzel list, nacti vybrany snippet
            if (e.Node.Nodes.Count == 0 && e.Node.ImageIndex == 2)
            {
                LoadSnippet(e.Node.Tag.ToString());
                
                tsbtnRefreshSnippet.Enabled = true;
                tsbtnSaveSnippet.Enabled = true;
            }
            else
            {
                ClearSnippet();
            }
        }

        /// <summary>
        /// Handles the Click event of the tsbtnSaveSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnSaveSnippet_Click(object sender, EventArgs e)
        {
            SaveSnippet(tvSnippets.SelectedNode.Tag.ToString());
        }

        /// <summary>
        /// Handles the Click event of the tsbtnRefreshSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnRefreshSnippet_Click(object sender, EventArgs e)
        {
            if(IsSnippetChanged && MessageBox.Show("Opravdu znovunačíst snippet?\nDojde k zapomenutí všech změn!", 
                    "Ověření", 
                    MessageBoxButtons.YesNo, 
                    MessageBoxIcon.Question, 
                    MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                LoadSnippet(tvSnippets.SelectedNode.Tag.ToString());
        }

        /// <summary>
        /// Handles the MouseDown event of the rtbCodeSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void rtbCodeSnippet_MouseDown(object sender, MouseEventArgs e)
        {
            //zjisti souradnice vudci textu a mysi a nastavi na toto misto kurzor
            int positionIndex = rtbCodeSnippet.GetCharIndexFromPosition(e.Location);
            rtbCodeSnippet.SelectionStart = positionIndex;
            rtbCodeSnippet.SelectionLength = 0;

            //vypocita souradnice vudci rohu obrazovky a posune jej pod radek textu
            Point menuPoint = rtbCodeSnippet.GetPositionFromCharIndex(positionIndex);
            menuPoint.Y += 12;

            //nacte informace o placeholderu, jestrli se na soucasne pozici nejaky nachazi
            PlaceholderDetailByCodePlace();

            //podle typu textu zobrazi prislusne menu
            if (rtbCodeSnippet.IsSelectionPlaceholder)
            {
                if (e.Button == MouseButtons.Right)
                    cmsMenuWithPlaceholder.Show(rtbCodeSnippet.PointToScreen(menuPoint));
            }
            else
            {
                if (e.Button == MouseButtons.Right)
                    cmsMenuWithoutPlaceholder.Show(rtbCodeSnippet.PointToScreen(menuPoint));
            }
        }

        /// <summary>
        /// Handles the Click event of the tsbtnCodeCut control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnCodeCut_Click(object sender, EventArgs e)
        {
            rtbCodeSnippet.Cut();
        }

        /// <summary>
        /// Handles the Click event of the tsbtnCodeCopy control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnCodeCopy_Click(object sender, EventArgs e)
        {
            rtbCodeSnippet.Copy();
        }

        /// <summary>
        /// Handles the Click event of the tsbtnCodePaste control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnCodePaste_Click(object sender, EventArgs e)
        {
            rtbCodeSnippet.Paste();
        }

        /// <summary>
        /// Handles the KeyDown event of the rtbCodeSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
        private void rtbCodeSnippet_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Home || e.KeyCode == Keys.End ||
                e.KeyCode == Keys.Left || e.KeyCode == Keys.Right || e.KeyCode == Keys.PageDown || e.KeyCode == Keys.PageUp)
            {
                PlaceholderDetailByCodePlace();
            }
        }

        /// <summary>
        /// Handles the Click event of the btnAddReference control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnAddReference_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtReference.Text))
                return;

            cs.CodeSnippet.Snippet.Imports.Import.Add(new ClassImportDetail(txtReference.Text));
            ReloadReferences();
        }

        /// <summary>
        /// Handles the Click event of the btnDeleteReference control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnDeleteReference_Click(object sender, EventArgs e)
        {
            if (lbReferences.SelectedIndex >= 0)
            {
                if (MessageBox.Show("Opravdu odstranit referenci " + ((ClassImportDetail)lbReferences.SelectedItem).Namespace + "?",
                    "Odstranění", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    cs.CodeSnippet.Snippet.Imports.Import.Remove((ClassImportDetail)lbReferences.SelectedItem);

                    ReloadReferences();
                }
            }
        }

        /// <summary>
        /// Handles the Click event of the tsbtnSearchSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsbtnSearchSnippet_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(tstxtSearchSnippetText.Text))
                return;

            FindInTreeView(tstxtSearchSnippetText.Text.ToLower(), tvSnippets.Nodes);
        }

        /// <summary>
        /// Handles the MouseDown event of the tvSnippets control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void tvSnippets_MouseDown(object sender, MouseEventArgs e)
        {
            tvSnippets.ContextMenuStrip = cmsTreeViewMenu;
        }

        /// <summary>
        /// Handles the Click event of the vytvořitSložkuToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void vytvořitSložkuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = tvSnippets.GetNodeAt(tvSnippets.PointToClient(new Point(cmsTreeViewMenu.Left, cmsTreeViewMenu.Top))); 
            
            if (node.Tag == null || string.IsNullOrEmpty((string)node.Tag))
            {
                MessageBox.Show("Na toto místo nelze přidat nová složka!", "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            frmInputDialog input = new frmInputDialog("Název nové složky:");
            if (input.ShowDialog() != DialogResult.OK)
                return;

            string path = (string)node.Tag + @"\" + input.Value;

            try
            {
                Directory.CreateDirectory(path);
                RefreshSnippetsTree();
            }
            catch (Exception exc)
            {
                MessageBox.Show("Složka nebyla vytvořena z důvodu následující chyby:\n" + exc.Message, "Vytvoření složky", MessageBoxButtons.OK, MessageBoxIcon.Error);   
            }
        }

        /// <summary>
        /// Handles the Click event of the vytvořitSnippetToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void vytvořitSnippetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = tvSnippets.GetNodeAt(tvSnippets.PointToClient(new Point(cmsTreeViewMenu.Left, cmsTreeViewMenu.Top))); 
            
            if (node.Tag == null || string.IsNullOrEmpty((string)node.Tag))
            {
                MessageBox.Show("Na toto místo nelze vložit snippet!", "Upozornění", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            frmInputDialog input = new frmInputDialog("Název nově vytvářeného snippetu:");
            if (input.ShowDialog() != DialogResult.OK)
                return;

            string path = (string)node.Tag + @"\" + input.Value + ".snippet";
            if (CreateNewSnippet(input.Value, path))
                RefreshSnippetsTree();
        }

        /// <summary>
        /// Handles the ModifiedChanged event of the rtbCodeSnippet control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void rtbCodeSnippet_ModifiedChanged(object sender, EventArgs e)
        {
            if (!IsSnippetChanged && isSnippetLoaded)
                IsSnippetChanged = true;
        }

        /// <summary>
        /// Handles the Click event of the tsmiCreatePlaceholder control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsmiCreatePlaceholder_Click(object sender, EventArgs e)
        {
            CreateNewPlaceholder(rtbCodeSnippet.GetWord());
        }

        /// <summary>
        /// Handles the Click event of the tsmiDeletePlaceholder control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void tsmiDeletePlaceholder_Click(object sender, EventArgs e)
        {
            DeletePlaceholder(rtbCodeSnippet.GetWord());
        }

        #region Udalosti pro zapis zmen hodnot

        /// <summary>
        /// Handles the SelectedIndexChanged event of the ddlLanguage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ddlLanguage_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Snippet.Code.Language = ((DropDownListItem)ddlLanguage.SelectedValue).Value;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the ddlKind control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ddlKind_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Snippet.Code.Kind = ((DropDownListItem)ddlKind.SelectedValue).Value;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtName_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Header.Title = txtName.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtShortcut control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtShortcut_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Header.Shortcut = txtShortcut.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtAuthor control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtAuthor_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Header.Author = txtAuthor.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtDescription control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtDescription_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Header.Description = txtDescription.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtHelpUrl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtHelpUrl_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded)
            {
                cs.CodeSnippet.Header.HelpUrl = txtHelpUrl.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtPlaceholderName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtPlaceholderName_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded && txtPlaceholderName.Tag != null && ((int)txtPlaceholderName.Tag) > -1)
            {
                cs.CodeSnippet.Snippet.Declarations.Literal[(int)txtPlaceholderName.Tag].ID = txtPlaceholderName.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtPlaceholderType control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtPlaceholderType_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded && txtPlaceholderName.Tag != null && ((int)txtPlaceholderName.Tag) > -1)
            {
                cs.CodeSnippet.Snippet.Declarations.Literal[(int)txtPlaceholderName.Tag].Type = txtPlaceholderType.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtPlaceholderDefaultValue control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtPlaceholderDefaultValue_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded && txtPlaceholderName.Tag != null && ((int)txtPlaceholderName.Tag) > -1)
            {
                cs.CodeSnippet.Snippet.Declarations.Literal[(int)txtPlaceholderName.Tag].Default = txtPlaceholderDefaultValue.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtPlaceholderToolTip control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtPlaceholderToolTip_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded && txtPlaceholderName.Tag != null && ((int)txtPlaceholderName.Tag) > -1)
            {
                cs.CodeSnippet.Snippet.Declarations.Literal[(int)txtPlaceholderName.Tag].ToolTip = txtPlaceholderToolTip.Text;
                IsSnippetChanged = true;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the txtPlaceholderFunction control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txtPlaceholderFunction_TextChanged(object sender, EventArgs e)
        {
            if (isSnippetLoaded && txtPlaceholderName.Tag != null && ((int)txtPlaceholderName.Tag) > -1)
            {
                cs.CodeSnippet.Snippet.Declarations.Literal[(int)txtPlaceholderName.Tag].Function = txtPlaceholderFunction.Text;
                IsSnippetChanged = true;
            }
        }

        #endregion

        #endregion


        #region Soukrome funkce

        /// <summary>
        /// Refreshes the snippets tree.
        /// </summary>
        private void RefreshSnippetsTree()
        {
            tvSnippets.Nodes.Clear();

            //vytvori uzel pro VS 2005 a naplni jej danymi snippety
            TreeNode tn2005 = new TreeNode("Visual Studio 2005", 0, 0);
            tvSnippets.Nodes.Add(tn2005);

            //visual basic
            TreeNode tn2005vb = new TreeNode("Visual Basic", 1, 1);
            tn2005vb.Tag = PathVS2005VB;
            tn2005.Nodes.Add(tn2005vb);

            InsertDirectoryToTree(ref tn2005vb, PathVS2005VB, true);

            //C#
            TreeNode tn2005cs = new TreeNode("C#", 1, 1);
            tn2005cs.Tag = PathVS2005CS;
            tn2005.Nodes.Add(tn2005cs);

            InsertDirectoryToTree(ref tn2005cs, PathVS2005CS, true);

            //vytvori uzel pro VS 2008 a naplni jej danymi snippety
            TreeNode tn2008 = new TreeNode("Visual Studio 2008", 0, 0);
            tvSnippets.Nodes.Add(tn2008);

            //visual basic
            TreeNode tn2008vb = new TreeNode("Visual Basic", 1, 1);
            tn2008vb.Tag = PathVS2008VB;
            tn2008.Nodes.Add(tn2008vb);

            InsertDirectoryToTree(ref tn2008vb, PathVS2008VB, true);

            //C#
            TreeNode tn2008cs = new TreeNode("C#", 1, 1);
            tn2008cs.Tag = PathVS2008CS;
            tn2008.Nodes.Add(tn2008cs);

            InsertDirectoryToTree(ref tn2005cs, PathVS2008CS, true);
        }

        /// <summary>
        /// Inserts the directory to tree.
        /// </summary>
        /// <param name="tn">The tn.</param>
        /// <param name="path">The path.</param>
        private void InsertDirectoryToTree(ref TreeNode tn, string path, bool isFirstNode)
        {
            TreeNode uzel = null;

            if (!isFirstNode)
            {
                //prida do stromu aktualni slozku
                uzel = new TreeNode(GetDirectory(path), 1, 1);
                uzel.Tag = path;
                tn.Nodes.Add(uzel);
            }
            else
                uzel = tn;

            //rekurzivne projde vsechny vnorene slozky
            string[] slozky;
            try
            {
                slozky = Directory.GetDirectories(path);
            }
            catch (Exception)
            {
                return;
            } 
            foreach (string slozka in slozky)
            {
                InsertDirectoryToTree(ref uzel, slozka, false);
            }

            //zapise jednotlive snippety ve slozce
            string[] soubory = Directory.GetFiles(path, "*.snippet", SearchOption.TopDirectoryOnly);
            foreach (string soubor in soubory)
            {
                TreeNode stn = new TreeNode(GetSnippetName(soubor), 2, 2);
                stn.Tag = soubor;

                uzel.Nodes.Add(stn);
            }

        }

        /// <summary>
        /// Gets the directory.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private string GetDirectory(string path)
        {
            string[] slozky = path.Split('\\');
            
            return slozky[slozky.Length - 1];
        }

        /// <summary>
        /// Gets the name of the snippet.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private string GetSnippetName(string path)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(path);

                //nacte z tela snippetu jeho nazev
                XmlNodeList xnl = doc.GetElementsByTagName("Title");
                if (xnl.Count > 0)
                    return xnl.Item(0).InnerText;

                //pokud nebyl element s nazvem nalezen, vrati nazev souboru
                return Path.GetFileNameWithoutExtension(path);
            }
            catch (Exception)
            {
                return Path.GetFileNameWithoutExtension(path);
            }
        }

        /// <summary>
        /// Creates the new snippet.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private bool CreateNewSnippet(string name, string path)
        {
            try
            {
                if (File.Exists(path))
                {
                    MessageBox.Show("Snippet se zadaným názvem již existuje!", "Vytvoření snippetu", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return false;
                }

                //zapise defaultni tvar snippetu
                StreamWriter sw = new StreamWriter(File.Create(path), Encoding.UTF8);
                sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                sw.WriteLine("<CodeSnippets xmlns=\"http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet\">");
                sw.WriteLine("  <CodeSnippet Format=\"1.0.0\">");
                sw.WriteLine("    <Header>");
                sw.WriteLine("      <Title>" + name + "</Title>");
                sw.WriteLine("      <Author></Author>");
                sw.WriteLine("      <Description></Description>");
                sw.WriteLine("      <Shortcut></Shortcut>");
                sw.WriteLine("    </Header>");
                sw.WriteLine("    <Snippet>");
                sw.WriteLine("      <Code Language=\"csharp\" />");
                sw.WriteLine("    </Snippet>");
                sw.WriteLine("  </CodeSnippet>");
                sw.WriteLine("</CodeSnippets>");
                sw.Flush();
                sw.Close();

                return true;
            }
            catch (Exception)
            {
                return false;
            }            
        }

        /// <summary>
        /// Clears the snippet.
        /// </summary>
        private void ClearSnippet()
        {
            //premaze object
            cs = new CodeSnippets();
            isSnippetLoaded = false;

            //smaze hodnoty poli
            //kod snippetu
            rtbCodeSnippet.Text = string.Empty;

            //zakladni nastaveni snippetu
            txtName.Text = string.Empty;
            txtAuthor.Text = string.Empty;
            txtDescription.Text = string.Empty;
            txtShortcut.Text = string.Empty;
            txtHelpUrl.Text = string.Empty;

            //nastaveni kodu
            ddlLanguage.SelectedIndex = 0;
            ddlKind.SelectedIndex = 0;
            txtDelimeter.Text = "$";

            //reference
            lbReferences.Items.Clear();
            txtReference.Text = string.Empty;

            //znepristupni tlacitka
            SetEnabledSnippetControls(false);
        }

        /// <summary>
        /// Loads the snippet.
        /// </summary>
        /// <param name="path">The path.</param>
        private void LoadSnippet(string path)
        {
            isSnippetLoaded = false;

            try
            {
                //provede deserializaci snippetu do vnitrni objektove struktury
                XmlSerializer serializer = new XmlSerializer(typeof(CodeSnippets), "http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet");
                XmlReader reader = XmlReader.Create(path);
                if (!serializer.CanDeserialize(reader))
                {
                    reader.Close();
                    return;
                }

                cs = (CodeSnippets)serializer.Deserialize(reader);

                reader.Close();
            }
            catch (Exception)
            {
                cs = new CodeSnippets();
                return;
            }

            //naplni polozky formulare
            //kod snippetu
            XmlDocument doc = new XmlDocument();
            doc.Load(path);

            //nacte z tela snippetu jeho nazev
            //protoze XmlSerializer neumi primo pracovat s uzly typu CDATA musi se nacteni teto casti trochu obejit
            XmlNodeList nodeList = doc.GetElementsByTagName("Code");
            if (nodeList.Count > 0)
                cs.CodeSnippet.Snippet.Code.Code = nodeList.Item(0).InnerText;
            rtbCodeSnippet.Text = cs.CodeSnippet.Snippet.Code.Code;


            //zakladni nastaveni snippetu
            txtName.Text = cs.CodeSnippet.Header.Title;
            txtAuthor.Text = cs.CodeSnippet.Header.Author;
            txtDescription.Text = cs.CodeSnippet.Header.Description;
            txtShortcut.Text = cs.CodeSnippet.Header.Shortcut;
            txtHelpUrl.Text = cs.CodeSnippet.Header.HelpUrl;

            //nastaveni kodu
            SelectValueInDropDownList(ref ddlLanguage, cs.CodeSnippet.Snippet.Code.Language);
            SelectValueInDropDownList(ref ddlKind, cs.CodeSnippet.Snippet.Code.Kind);
            if (cs.CodeSnippet.Snippet.Code.Delimiter.Length < 1)
                cs.CodeSnippet.Snippet.Code.Delimiter = "$";
            txtDelimeter.Text = cs.CodeSnippet.Snippet.Code.Delimiter;
            rtbCodeSnippet.Delimiter = cs.CodeSnippet.Snippet.Code.Delimiter;

            //reference
            ReloadReferences();

            //smaze pole pro placeholder
            txtPlaceholderDefaultValue.Text = string.Empty;
            txtPlaceholderFunction.Text = string.Empty;
            txtPlaceholderName.Text = string.Empty;
            txtPlaceholderToolTip.Text = string.Empty;
            txtPlaceholderType.Text = string.Empty;

            isSnippetLoaded = true;
            IsSnippetChanged = false;

        }

        /// <summary>
        /// Saves the snippet.
        /// </summary>
        /// <param name="path">The path.</param>
        private void SaveSnippet(string path)
        {
            //ulozi kod 
            cs.CodeSnippet.Snippet.Code.Code = rtbCodeSnippet.Text;

            //serializuje objekt do xml struktury - snippet
            XmlSerializer serializer = new XmlSerializer(cs.GetType(), "http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet");

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.NewLineChars = Environment.NewLine;
            settings.Indent = true;
            settings.IndentChars = "\t";

            //zapise data
            XmlWriter writer = XmlWriter.Create(path, settings);
            serializer.Serialize(writer, cs);

            //ukonci praci se souborem
            writer.Flush();
            writer.Close();
        }

        /// <summary>
        /// Selects the value in drop down list.
        /// </summary>
        /// <param name="value">The value.</param>
        private void SelectValueInDropDownList(ref ComboBox control, string value)
        {
            foreach (DropDownListItem item in control.Items)
            {
                if (item.Value == value)
                {
                    control.SelectedItem = item;
                    return;
                }
            }

            //polozka nebyla nalezena -> nastavi defaultne prvni polozku
            control.SelectedIndex = 0;
        }

        /// <summary>
        /// Placeholders the detail by code place.
        /// </summary>
        private void PlaceholderDetailByCodePlace()
        {
            if (rtbCodeSnippet.IsSelectionPlaceholder)
            {
                //ziska slovo, na kterem je kurzor
                string selectWord = rtbCodeSnippet.GetWord();
                txtPlaceholderName.Tag = null;

                //projde vsechny zname placeholdery a nalezene ten, ne kterem stojime a zapise ho do textovych poli
                for (int i = 0; i < cs.CodeSnippet.Snippet.Declarations.Literal.Count; i++)
                {
                    ClassPlaceholder item = cs.CodeSnippet.Snippet.Declarations.Literal[i];

                    if (selectWord == cs.CodeSnippet.Snippet.Code.Delimiter + item.ID + cs.CodeSnippet.Snippet.Code.Delimiter)
                    {
                        txtPlaceholderDefaultValue.Text = item.Default;
                        txtPlaceholderFunction.Text = item.Function;
                        txtPlaceholderName.Text = item.ID;
                        txtPlaceholderToolTip.Text = item.ToolTip;
                        txtPlaceholderType.Text = item.Type;

                        rtbCodeSnippet.SelectionStart--;
                        bool leftIsPlaceholder = rtbCodeSnippet.IsSelectionPlaceholder;
                        rtbCodeSnippet.SelectionStart += 2;
                        bool rightIsPlaceholder = rtbCodeSnippet.IsSelectionPlaceholder;
                        rtbCodeSnippet.SelectionStart--;

                        txtPlaceholderName.Tag = (leftIsPlaceholder && rightIsPlaceholder && true ? i : -1);
                        break;
                    }
                }

            }
            else
            {
                txtPlaceholderDefaultValue.Text = string.Empty;
                txtPlaceholderFunction.Text = string.Empty;
                txtPlaceholderName.Text = string.Empty;
                txtPlaceholderToolTip.Text = string.Empty;
                txtPlaceholderType.Text = string.Empty;

                txtPlaceholderName.Tag = null;
            }
        }

        /// <summary>
        /// Reloads the references.
        /// </summary>
        private void ReloadReferences()
        {
            lbReferences.Items.Clear();
            lbReferences.Items.AddRange(cs.CodeSnippet.Snippet.Imports.Import.ToArray());
            txtReference.Text = string.Empty;
        }

        /// <summary>
        /// Finds the in tree view.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <returns></returns>
        private bool FindInTreeView(string text, TreeNodeCollection tnc)
        {
            //prohledavani do hloubky
            foreach (TreeNode node in tnc)
            {
                //je-li uzel slozka, prohledej ji
                if (node.ImageIndex < 2)
                {
                    if (FindInTreeView(text, node.Nodes))
                        return true;
                }
                else
                {
                    if (node.Text.ToLower().Contains(text))
                    {
                        tvSnippets.SelectedNode = node;
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Sets the enabled snippet controls.
        /// </summary>
        /// <param name="value">if set to <c>true</c> [value].</param>
        private void SetEnabledSnippetControls(bool value)
        {
            this.Text = "Code Snippets Editor" + (value ? " *" : string.Empty );
            
            tsbtnRefreshSnippet.Enabled = value;
            tsbtnSaveSnippet.Enabled = value;
        }

        /// <summary>
        /// Determines whether [is placeholder exists] [the specified name].
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private ClassPlaceholder IsPlaceholderExists(string name)
        { 
            //projde seznam dosavadnich palceholderu a overi, zda vnem zadany placeholder existuje
            foreach (ClassPlaceholder item in cs.CodeSnippet.Snippet.Declarations.Literal)
            {
                if (item.ID == name)
                {
                    return item;
                }
            }

            return null;
        }

        /// <summary>
        /// Creates the new placeholder.
        /// </summary>
        /// <param name="name">The name.</param>
        private void CreateNewPlaceholder(string name)
        { 
            if(IsPlaceholderExists(name) != null)
            {
                MessageBox.Show("Placeholder již existuje!");
                return;
            }

            //vytvori placeholder
            cs.CodeSnippet.Snippet.Declarations.Literal.Add(new ClassPlaceholder(name, string.Empty, string.Empty, string.Empty, string.Empty, true));
        
            //prepise vsechny vyskyty v kodu
            rtbCodeSnippet.Text = rtbCodeSnippet.Text.Replace(name, "$" + name + "$");
        }

        /// <summary>
        /// Deletes the placeholder.
        /// </summary>
        /// <param name="name">The name.</param>
        private void DeletePlaceholder(string name)
        { 
            //overi, ze zadany text je nazev existujiciho placeholderu
            if (!name.StartsWith("$") || !name.EndsWith("$"))
            {
                MessageBox.Show("Nejedná se o placeholder!");
                return;
            }
            ClassPlaceholder placeholder = IsPlaceholderExists(name.Trim('$'));
            if (placeholder == null)
            {
                MessageBox.Show("Placeholder neexistuje!");
                return;
            }

            //odstrani objekt placeholderu
            cs.CodeSnippet.Snippet.Declarations.Literal.Remove(placeholder);

            rtbCodeSnippet.Text = rtbCodeSnippet.Text.Replace(name, name.Trim('$'));
        }

        #endregion
    }
}
